/**
 * 
 */
package kevin.study.zephyr.domain.dao.soda;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import kevin.study.zephyr.domain.soda.Constraint;
import kevin.study.zephyr.domain.soda.Constraints;
import kevin.study.zephyr.domain.soda.Query;

import org.apache.commons.collections.MultiMap;
import org.apache.commons.collections.map.MultiValueMap;


/**
 * 面向DAO的,采用SODA方式进行查询 此Query的用法和标准的SODA稍有不同
 * 此Query不能指定根查询节点的约束.此节点的约束由DAO指定(因为DAO使用了泛型,若此处指定的话,泛型cast的时候就会抛CastError的异常)
 * 
 * @author Kevin.Huang
 * @createtime 2007-9-30
 */
public class ZQuery implements Query {
	/**
	 * 此节点对应的域
	 */
	private String field = null;

	/**
	 * 所有的约束的集合
	 */

	private MultiMap constraints;

	private List< ZOrder > orders;

	private List< ZComparator > comparators;

	/**
	 * 父节点
	 */
	private ZQuery parentQuery;

	/**
	 * 子节点
	 */
	private Map< String, ZQuery > querys = new HashMap< String, ZQuery >();

	public ZQuery() {
		this.constraints = new MultiValueMap();
		this.orders = new ArrayList< ZOrder >();
		this.comparators = new ArrayList< ZComparator >();
	}

	protected ZQuery(String field, ZQuery parentQuery) {
		this.field = field;
		this.parentQuery = parentQuery;
		this.constraints = parentQuery.getConstraint();
		this.orders = parentQuery.getOrders();
		this.comparators = parentQuery.getComparators();
	}

	public Constraint constrain(Object constraint) {
		if (field == null) {
			throw new RuntimeException("The Root Query Node can constraint only one condition!");
		}
		ZConstraint c = new ZConstraint(this, constraint);
		constraints.put(this.field, c);
		return c;
	}

	@SuppressWarnings("unchecked")
	public Constraints constraints() {
		return new ZConstraints((Collection< ZConstraint >) constraints.get(this.field));
	}

	public Query descend(String fieldName) {
		if (querys.keySet().contains(fieldName)) {
			return querys.get(fieldName);
		} else {
			ZQuery q = new ZQuery((this.field == null ? fieldName : (this.field + "." + fieldName)), this);
			querys.put(fieldName, q);
			return q;
		}

	}

	public Query orderAscending() {
		if (field == null) {
			throw new RuntimeException("The Root Query Node cannot make order!");
		}
		this.orders.add(new ZOrder(this.field, true));
		return this;
	}

	public Query orderDescending() {
		if (field == null) {
			throw new RuntimeException("The Root Query Node cannot make order!");
		}
		this.orders.add(new ZOrder(this.field, false));
		return this;
	}

	@SuppressWarnings("unchecked")
	public Query sortBy(Comparator comparator) {
		this.comparators.add(new ZComparator(this.field, comparator));
		return this;
	}

	/**
	 * @return the field
	 */
	public String getField() {
		return field;
	}

	/**
	 * @return the constraints
	 */
	public MultiMap getConstraint() {
		return constraints;
	}

	/**
	 * @return the querys
	 */
	public Map< String, ZQuery > getQuerys() {
		return querys;
	}

	/**
	 * @return the parentQuery
	 */
	public ZQuery getParentQuery() {
		return parentQuery;
	}

	/**
	 * @return the orders
	 */
	public List< ZOrder > getOrders() {
		return orders;
	}

	/**
	 * @return the comparators
	 */
	public List< ZComparator > getComparators() {
		return comparators;
	}
}
